/* 
 * Copyright (C) 2012 UTSChedule
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package utsc.apps.utschedule.ui;

import java.util.Calendar;

import utsc.apps.utschedule.R;
import utsc.apps.utschedule.UTSCheduleApp;
import utsc.apps.utschedule.classes.Course;
import utsc.apps.utschedule.classes.Timetable;
import utsc.apps.utschedule.services.TimetableDataService;
import utsc.apps.utschedule.ui.activities.CourseDetailActivity;
import utsc.apps.utschedule.ui.activities.CourseFormActivity;
import utsc.apps.utschedule.ui.activities.TimetableFormActivity;
import utsc.apps.utschedule.ui.interfaces.TimetableActivity;
import utsc.apps.utschedule.ui.interfaces.ViewCallable;
import utsc.apps.utschedule.util.TimetableHelper;
import utsc.apps.utschedule.util.database.DatabaseManager;
import utsc.apps.utschedule.widget.EventBlockView;
import utsc.apps.utschedule.widget.TimeBlockLayout;
import utsc.apps.utschedule.widget.TimeBlockView;
import utsc.apps.utschedule.widget.TimerWeekHeaderLayout;
import utsc.apps.utschedule.widget.TimerWeekHeaderLayout.OnDaySelectedListener;
import android.app.Activity;
import android.content.Intent;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;

import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.app.SherlockFragmentActivity;

/**
 * This is a fragment used to show timetable schedule.
 *
 */
public class ScheduleFragment extends SherlockFragment implements TimetableActivity{
	public static final String TAG="ScheduleFragment"; 
	private TimeBlockLayout _timeBlockLayout;
	private LinearLayout _emptyTimetableLayout;
	private Button _btnAddNewTimetable;
	private boolean _showDay;
	private View _fragment;
	private TimerWeekHeaderLayout _weekHeaderLayout;
	private static final String ARGS_WEEKNUM="weekNum";
	private static final String ARGS_SHOWDAY="showDay";
	private static final String ARGS_DAY_OF_YEAR="dayOfYear";
	private int _weekNum;
	private int _dayOfYear;
	private UTSCheduleApp app;
	private Timetable currentTimetable;
	private static int _globalScrollPosition;
	private int _currentScrollPosition;
	private ScrollView _blocklayoutScrollView;
	private OnDaySelectedListener _onHeaderDaySelectedListener;
	private static int _startWeek=-99;
	private static int _endWeek=-99;
	private SparseBooleanArray _shownOddWeek;
	private static long _now;
	
	private ViewCallable<Course> _courseViewCallable=new ViewCallable<Course>() {

		@Override
		public void updateDB(Course object) {
			set_refreshView(true);
			DatabaseManager.getInstance(getSherlockActivity().getApplicationContext()).updateCourse(object);
			 //Log.d(TAG,"starting service");
	            Intent i= new Intent(getSherlockActivity(), TimetableDataService.class);
	            i.putExtra(TimetableDataService.REQUEST_REFRESH, TimetableDataService.REFRESH_COURSES);
	            getSherlockActivity().startService(i);
	            
		}
		
	};
	
	
	/**
	 * Return a new {@link utsc.apps.utschedule.ui.ScheduleFragment} instance by
	 * providing the weeknumber and whether of not to display as day view mode.
	 * 
	 * @param weekNumber -the week number of year
	 * @param _showDay -true to display as day mode, otherwise display as week mode
	 * @return 
	 */
	public static ScheduleFragment newInstance(int weekNumber, boolean _showDay){
		ScheduleFragment fragment=new ScheduleFragment();
		Bundle args=new Bundle();
		args.putInt(ARGS_WEEKNUM, weekNumber);
		args.putInt(ARGS_DAY_OF_YEAR, TimetableHelper.getDayOfYear(weekNumber, Calendar.WEEK_OF_YEAR));
		args.putBoolean(ARGS_SHOWDAY, _showDay);
		fragment.setArguments(args);
		return fragment;
	}
	
	/**
	 * Return a new {@link utsc.apps.utschedule.ui.ScheduleFragment} instance by
	 * providing day of year. Note that this method will always return an instance that will display in day mode.
	 * 
	 * @param dayOfYear -the day number of the year
	 * @return 
	 */
	public static ScheduleFragment newInstance(int dayOfYear){
		ScheduleFragment fragment=new ScheduleFragment();
		Bundle args=new Bundle();
		args.putInt(ARGS_WEEKNUM, TimetableHelper.getWeekOfYear(dayOfYear, Calendar.DAY_OF_YEAR));
		args.putInt(ARGS_DAY_OF_YEAR, dayOfYear);
		args.putBoolean(ARGS_SHOWDAY, true);
		fragment.setArguments(args);
		return fragment;
	}
	
	public int get_dayOfYear() {
		return _dayOfYear;
	}
	
	public void setWeekOrDayOfYear(int value, int calendarFieldType){
		if (calendarFieldType==Calendar.DAY_OF_YEAR) {
			set_dayOfYear(value);
		}else {
			set_weekNum(value);
		}
	}
	
	/**
	 * Set the day of year of this instance (
	 * {@link utsc.apps.utschedule.ui.ScheduleFragment}), this method will also
	 * refresh the underlying view accordingly.
	 * 
	 * @param _dayOfYear
	 */
	private void set_dayOfYear(int _dayOfYear) {
		this._dayOfYear = _dayOfYear;
		this._weekNum=TimetableHelper.getWeekOfYear(_dayOfYear, Calendar.DAY_OF_YEAR);
		getArguments().putInt(ARGS_WEEKNUM, _weekNum);
		getArguments().putInt(ARGS_DAY_OF_YEAR, _dayOfYear);
		if (currentTimetable!=null) {
			refresh();
		}
		
		//setupHiddenOddWeeks();
		//_timeBlockLayout.refreshCourseBlocks(TimetableHelper.getWeekDay(_dayOfYear, Calendar.DAY_OF_YEAR),_shownOddWeek);
	}
	
	/**
	 * Set the week of year of this instance (
	 * {@link utsc.apps.utschedule.ui.ScheduleFragment}), this method will also
	 * refresh the underlying view accordingly.
	 * 
	 * @param _weekNum
	 */
	private void set_weekNum(int _weekNum) {
		this._weekNum = _weekNum;
		this._dayOfYear=TimetableHelper.getDayOfYear(_weekNum, Calendar.WEEK_OF_YEAR);
		getArguments().putInt(ARGS_WEEKNUM, _weekNum);
		getArguments().putInt(ARGS_DAY_OF_YEAR, _dayOfYear);
		if (_weekHeaderLayout!=null && currentTimetable!=null) {
			_weekHeaderLayout.set_weekNumber(_weekNum);
			refresh();
		}
	}
	
	Runnable scrollRunnable=new Runnable() {
		
		@Override
		public void run() {
			_blocklayoutScrollView.scrollTo(0, _currentScrollPosition);
		}
	};
	
	/**
	 * Update the scroll position to {@code scrollPosition} in y axis.
	 * @param scrollPosition -the new y position
	 */
	public void scrollToY(int scrollPosition) {
		if (_currentScrollPosition!=scrollPosition) {
			_currentScrollPosition=scrollPosition;
			if (_blocklayoutScrollView!=null) {
				_blocklayoutScrollView.post(scrollRunnable);
			}else {
				//Log.d("scheduleFragment", "no scrollview found");
			}
		}
		// we also update the global scroll position to synchronize the y position 
		_globalScrollPosition=scrollPosition;
	}
	
	public int get_globalScrollPosition() {
		if (_blocklayoutScrollView!=null) {
			_globalScrollPosition=_blocklayoutScrollView.getScrollY();
		}
		return _globalScrollPosition;
	}
	
	/**
	 * This method will refresh the instance ({@link  utsc.apps.utschedule.ui.ScheduleFragment }) if needed.
	 */
	public void refresh() {
		if (_timeBlockLayout.is_refreshView()) {
			refreshTimetable();
			if (currentTimetable==null) {
				_timeBlockLayout.setEnabled(false);
				_btnAddNewTimetable.setOnClickListener(this);
			}else {
				_emptyTimetableLayout.setVisibility(View.GONE);
				
				if (_showDay) {
					_timeBlockLayout.refreshCourseBlocks(currentTimetable.get_courseList(),TimetableHelper.getWeekDay(_dayOfYear, Calendar.DAY_OF_YEAR),_shownOddWeek,_courseViewCallable);
				}else {
					_timeBlockLayout.refreshCourseBlocks(currentTimetable.get_courseList(),_shownOddWeek,_courseViewCallable);
				}
			}
		}else {
			//Log.d(TAG, "refresh non update");
			if (currentTimetable!=null) {
				setupHiddenOddWeeks();
				if (_showDay) {
					_timeBlockLayout.refreshCourseBlocks(currentTimetable.get_courseList(),TimetableHelper.getWeekDay(_dayOfYear, Calendar.DAY_OF_YEAR),_shownOddWeek,_courseViewCallable);
				}else {
					_timeBlockLayout.refreshCourseBlocks(currentTimetable.get_courseList(),_shownOddWeek,_courseViewCallable);
				}
			}
		}
	}
	
	public int get_weekNum() {
		return _weekNum;
	}
	
	private void refreshTimetable(){
		//Log.d(TAG, "refresh!!!!");
		SherlockFragmentActivity activity= getSherlockActivity();
			app=(UTSCheduleApp)activity.getApplication();
		currentTimetable=app.get_currentActiveTimetable();
		if (currentTimetable!=null) {
			_startWeek=TimetableHelper.getWeekOfYear(currentTimetable.get_startdate());
			setupHiddenOddWeeks();
		}
		
		//TimeBlockLayout.set_startWeek();
	}
	
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		
		//try to get the show day argument if we have it
		if (savedInstanceState!=null) {
			_showDay=savedInstanceState.getBoolean(ARGS_SHOWDAY);
		}else {
			Bundle arguments=getArguments();
			_showDay=arguments!=null?arguments.getBoolean(ARGS_SHOWDAY):true;
		}
		
		int layoutId=R.layout.fragment_week;
		
		//set the different layout based on different modes
		if (_showDay) {
			layoutId=R.layout.fragment_day;
		}
		
		_fragment=inflater.inflate(layoutId, container,false);	
		
		return _fragment;
	}
	

	/**
	 * This is a general helper method to setup the fragment with the existing fragment view.
	 */
	private void setupFragment() {
		refreshTimetable();
		
		//if (_timeBlockLayout==null) {
			_timeBlockLayout=(TimeBlockLayout)_fragment.findViewById(R.id.blocks);
			//get the reference of the empty layout 
			_emptyTimetableLayout=(LinearLayout) _fragment.findViewById(R.id.empty_timetable_layout);
			_btnAddNewTimetable=(Button) _fragment.findViewById(R.id.btn_add_new_timetable);
			//get the top level scroll view
			_blocklayoutScrollView=(ScrollView)_fragment.findViewById(R.id.time_blocklayout);
			
		//}
		
		
		_timeBlockLayout.set_blockViewOnClickListener(this);
		
		
		if (!_showDay) {
			//only get the week header if we are not in day mode
			_weekHeaderLayout=(TimerWeekHeaderLayout) _fragment.findViewById(R.id.weekheader_layout);
			_weekHeaderLayout.set_weekNumber(_weekNum);
			_weekHeaderLayout.setHeaderOnClickListener(_onHeaderDaySelectedListener);
		}
		
		//we can find anything from db
		//show the empty layout
		if (currentTimetable==null) {
			_timeBlockLayout.setEnabled(false);
			_btnAddNewTimetable.setOnClickListener(this);
		}else {
			_emptyTimetableLayout.setVisibility(View.GONE);
		}
	}
	
	/**
	 * A wrapper method of {@code TimeBlockLayout.is_refreshView()}.
	 * @return
	 */
	public boolean is_refreshView() {
		return _timeBlockLayout.is_refreshView();
	}
	
	/**
	 * A wrapper method of {@code TimeBlockLayout.set_refreshView(refreshView)}.
	 * @param refreshView
	 */
	public void set_refreshView(boolean refreshView){
		_timeBlockLayout.set_refreshView(refreshView);
	}
	
	@Override
	public void onSaveInstanceState(Bundle outState) {
		outState.putInt(ARGS_DAY_OF_YEAR, _dayOfYear);
		outState.putInt(ARGS_WEEKNUM, _weekNum);
		outState.putBoolean(ARGS_SHOWDAY, _showDay);
		super.onSaveInstanceState(outState);
	}
	
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		//try to setup the important fields from the argument list
		//if nothing, try to initialize them with the most current time/date
		if (savedInstanceState!=null) {
				_dayOfYear=savedInstanceState.getInt(ARGS_DAY_OF_YEAR,TimetableHelper.getDayOfYear());
				_weekNum=savedInstanceState.getInt(ARGS_WEEKNUM, TimetableHelper.getCurrentWeekNumber());
		}else {
				Bundle arguments=getArguments();
				_dayOfYear=arguments!=null?arguments.getInt(ARGS_DAY_OF_YEAR):TimetableHelper.getDayOfYear();
				_weekNum=arguments!=null?arguments.getInt(ARGS_WEEKNUM):TimetableHelper.getCurrentWeekNumber();
		}
		setupFragment();
	}
	
/*	@Override
	public void onViewCreated(View view, Bundle savedInstanceState) {
		super.onViewCreated(view, savedInstanceState);

		UTSCheduleApp app=(UTSCheduleApp) getSherlockActivity().getApplication();
		Timetable currentTimetable=app.get_currentActiveTimetable();
		if (currentTimetable!=null) {
			_emptyTimetableLayout.setVisibility(View.GONE);
			_timeBlockLayout.set_refreshView(true);
			_timeBlockLayout.setCourseBlocks(currentTimetable.get_courses());
		}
		
	}*/

	/*@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		_quickAction=new QuickActionBar(getSherlockActivity());
		QuickAction addItem=new QuickAction(getSherlockActivity(),R.drawable.ic_action_plus, "Add");
		QuickAction deleteItem=new QuickAction(getSherlockActivity(),R.drawable.ic_action_cross, "Delete");
		_quickAction.addQuickAction(addItem);
		_quickAction.addQuickAction(deleteItem);
		_quickAction.setOnQuickActionClickListener(new OnQuickActionClickListener() {
			
			@Override
			public void onQuickActionClicked(QuickActionWidget widget, int position) {
				Toast.makeText(getSherlockActivity(), position+"", Toast.LENGTH_SHORT).show();
			}
		});
		
	}*/
	@Override
	public void onResume() {
		super.onResume();
		_timeBlockLayout.set_blockViewOnClickListener(this);
		//currentTimetable=app.get_currentActiveTimetable();
		//resume the fragment by refreshing all the underlying views
		if (currentTimetable!=null) {
			_timeBlockLayout.setEnabled(true);
			_emptyTimetableLayout.setVisibility(View.INVISIBLE);
			//TimeBlockLayout.set_refreshView(true);
			if (_shownOddWeek==null) {
				setupHiddenOddWeeks();
			}
			if (_showDay) {
				_timeBlockLayout.refreshCourseBlocks(currentTimetable.get_courseList(),TimetableHelper.getWeekDay(_dayOfYear, Calendar.DAY_OF_YEAR),_shownOddWeek,_courseViewCallable);
			}else {
				_timeBlockLayout.refreshCourseBlocks(currentTimetable.get_courseList(),_shownOddWeek,_courseViewCallable);
			}
			//_now=System.currentTimeMillis();
			//_globalScrollPosition=_timeBlockLayout.get_timeRulerGridView().getTimeVerticalOffset(_now);
			//scrollToY(_globalScrollPosition);
		}
	}
	
	/*@Override
	public void onPause() {
		super.onPause();
		if (_quickAction.isShowing()) {
			_quickAction.dismiss();
		}
		//_quickAction=null;
		//_timeBlockLayout.set_blockViewOnClickListener(null);
		//_timeBlockLayout.removeAllViews();
		//unbindDrawables(_fragment);
		//DatabaseManager.release();
	}
	*/
	@Override
	public void onDestroy() {
		super.onDestroy();
		
	}
	
	@Override
	public void onDetach() {
		super.onDetach();
		//try to destroy all the child views
				if (_timeBlockLayout!=null) {
					
					if (_weekHeaderLayout!=null) {
						//Log.d(TAG, "destory "+_showDay);
						_weekHeaderLayout.setHeaderOnClickListener(null);
						//_onHeaderDaySelectedListener=null;
					}
					_timeBlockLayout.set_blockViewOnClickListener(null);
					_timeBlockLayout.removeAllViews();
				}
	}
	
	@Override
	public void onInflate(Activity activity, AttributeSet attrs,
			Bundle savedInstanceState) {
		super.onInflate(activity, attrs, savedInstanceState);
		TypedArray a = activity.obtainStyledAttributes(attrs,
                R.styleable.TimeFragment);
		//we also try to initialize the important field from the layout xml file as possible
        _showDay= a.getBoolean(R.styleable.TimeFragment_showDay, false);
        a.recycle();
	}
	
	/**
	 * This overridden method of {@code startActivityForResult} is actually calling {@code super.startActivity(intent)} at the end.
	 * The purpose is to send the proper request code when we start a new activity.
	 */
	@Override
	public void startActivityForResult(Intent intent, int requestCode) {
		intent.putExtra("RequestCode", requestCode);
		// we should always call the actual startActivityForResult method from the parent 
		super.startActivity(intent);
	}
	
	@Override
	public void onClick(View v) {
		if (v instanceof TimeBlockView) {
			Intent courseForm = new Intent(getSherlockActivity(), CourseFormActivity.class);
			courseForm.putExtra("SelectedHour", ((TimeBlockView) v).get_hourPosition());
			if (_showDay) {
				courseForm.putExtra("SelectedWeekday", TimetableHelper.getWeekDay(_dayOfYear, Calendar.DAY_OF_YEAR));
			}else {
				courseForm.putExtra("SelectedWeekday", ((TimeBlockView) v).get_columnPosition());
			}
			
			startActivityForResult(courseForm, RESULT_NEW_COURSE);
		}else if (v instanceof Button) {
			if (v.getId()==R.id.btn_add_new_timetable) {
				Intent timetableForm=new Intent(getSherlockActivity(),TimetableFormActivity.class);
				startActivityForResult(timetableForm, RESULT_NEW_TIMETABLE);
			}
		}else if (v instanceof EventBlockView) {
			//Log.d("eventBlockView", "Click!");
			//_quickAction.show(v);
			final EventBlockView courseBlockView=(EventBlockView) v; 
			Intent courseDetail=new Intent(getSherlockActivity(),CourseDetailActivity.class);
			courseDetail.putExtra(CourseDetailActivity.REQUEST_COURSE_KEY, courseBlockView.get_course().get_courseID());
			startActivity(courseDetail);
			//startActivityForResult(courseDetail, res)
		}
	}
	/*
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		switch (requestCode) {
			case RESULT_NEW_COURSE:
				if (resultCode==Activity.RESULT_OK) {
					_timeBlockLayout.setEnabled(true);
					TimeBlockLayout.set_refreshView(true);
					//_timeBlockLayout.invalidate();
					//Course c=(Course) data.getSerializableExtra("CourseFormResult");
					//_timeBlockLayout.addEventBlock(c);
					//_timeBlockLayout.add_course(c);
				}
				else if (resultCode==Activity.RESULT_CANCELED) {
				//	Context c=getSherlockActivity();
					//Toast.makeText(c, AppUtils.TOAST_ADD_COURSE_CANCELLED_STRING, Toast.LENGTH_SHORT).show();
				}
				break;
				
			case RESULT_NEW_TIMETABLE:
				if (resultCode==Activity.RESULT_OK) {
					TimeBlockLayout.set_refreshView(true);
					_emptyTimetableLayout.setVisibility(View.GONE);
					_timeBlockLayout.setEnabled(true);
				}
				
				break;
			default:
				break;
		}
	}*/

	public OnDaySelectedListener get_onHeaderDaySelectedListener() {
		return _onHeaderDaySelectedListener;
	}

	public void setOnWeekHeaderDaySelectedListener(
			OnDaySelectedListener _onHeaderDaySelectedListener) {
		if (!_showDay) {
			this._onHeaderDaySelectedListener=_onHeaderDaySelectedListener;
			//if (_weekHeaderLayout!=null) {
				
			//}
		}
		//this._onHeaderDaySelectedListener = _onHeaderDaySelectedListener;
	}
	public static int get_startWeek() {
		return _startWeek;
	}

	public static void set_startWeek(int _startWeek) {
		ScheduleFragment._startWeek = _startWeek;
	}
	
	public void scrollToNow(){
		//_globalScrollPosition=_timeBlockLayout.get_timeRulerGridView().getTimeVerticalOffset(_now);
		//scrollToY(_globalScrollPosition);
	}
	
	private void setupHiddenOddWeeks(){
		
		if (_startWeek!=-99) {
			if (_endWeek==-99) {
				//int nextTerm=TimetableHelper.getSession(TimetableHelper.getMonth(Calendar.WEEK_OF_YEAR, _startWeek));
				String session=currentTimetable.get_session();
				
				if (session.equals("Winter")) {
					_endWeek=TimetableHelper.getStartWeekOfYearByMonth(Calendar.MAY)+1;
				}else if (session.equals("Summer")) {
					_endWeek=TimetableHelper.getStartWeekOfYearByMonth(Calendar.SEPTEMBER)+1;
				}else {
					_endWeek=TimetableHelper.getStartWeekOfYearByMonth(Calendar.JANUARY)+1;
				}
			}
			//Log.d(TAG, "oddweeks: "+_weekNum+" "+_startWeek);
			if (_weekNum>0) {
				int currentWeek=_weekNum-_startWeek+1;
				if (_shownOddWeek==null) {
					_shownOddWeek=new SparseBooleanArray();
				}/*else {
					_shownOddWeek.clear();
				}*/
				
				if (_weekNum<_endWeek && currentWeek>0) {
					if (currentWeek%4==0) {
						_shownOddWeek.put(4, true);
					}else {
						_shownOddWeek.put(4, false);
					}
					if (currentWeek%3==0) {
						_shownOddWeek.put(3, true);
					}else {
						_shownOddWeek.put(3, false);
					}
					if (currentWeek%2==0) {
						_shownOddWeek.put(2, true);
					}else {
						_shownOddWeek.put(2, false);
					}
					_shownOddWeek.put(1, true);
				}else {
					_shownOddWeek.put(4, false);
					_shownOddWeek.put(3, false);
					_shownOddWeek.put(2, false);
					_shownOddWeek.put(1, false);
					_shownOddWeek.put(0,true);
				}
				
				
			}
		}
	}
}
